import logging
import os
from typing import Any, Dict, List, Literal, Optional, Union

from fastapi import FastAPI, HTTPException, Request
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel, ConfigDict, Field
from services.std_service import StdService

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# 创建 FastAPI 应用
app = FastAPI(title="金融术语标准化API", description="金融术语处理工具集后端API服务")

# 配置跨域资源共享
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# 从环境变量加载配置
MILVUS_HOST = os.getenv("MILVUS_HOST", "localhost")
MILVUS_PORT = os.getenv("MILVUS_PORT", "19530")
EMBEDDING_PROVIDER = os.getenv("EMBEDDING_PROVIDER", "huggingface")
EMBEDDING_MODEL = os.getenv("EMBEDDING_MODEL", "./bge-m3")
COLLECTION_NAME = os.getenv("COLLECTION_NAME", "financial_concepts")

# 初始化术语标准化服务（单例）
std_service = StdService(
    provider=EMBEDDING_PROVIDER,
    model=EMBEDDING_MODEL,
    db_path=f"http://{MILVUS_HOST}:{MILVUS_PORT}",
    collection_name=COLLECTION_NAME,
)


# 基础模型类
class BaseInputModel(BaseModel):
    """基础输入模型，包含所有模型共享的字段"""

    model_config = ConfigDict(arbitrary_types_allowed=True)

    llmOptions: Dict[str, str] = Field(
        default_factory=lambda: {"provider": "ollama", "model": "qwen2.5:7b"},
        description="大语言模型配置选项",
    )


class EmbeddingOptions(BaseModel):
    """向量数据库配置选项"""

    provider: Literal["huggingface", "openai", "bedrock"] = Field(
        default=os.getenv("EMBEDDING_PROVIDER", "huggingface"),
        description="向量数据库提供商",
    )
    model: str = Field(
        default=os.getenv("EMBEDDING_MODEL", "./bge-m3/"), description="嵌入模型名称"
    )
    dbName: str = Field(
        default=os.getenv("VECTOR_DB_NAME", "finance_terms_bge_m3"),
        description="向量数据库名称",
    )
    collectionName: str = Field(
        default=os.getenv("COLLECTION_NAME", "financial_concepts"),
        description="集合名称",
    )


class TextInput(BaseInputModel):
    """文本输入模型，用于标准化和命名实体识别"""

    text: str = Field(..., description="输入文本")
    termTypes: Dict[str, str] = Field(
        default_factory=lambda: {"FINTERM": "金融术语"},
        description="术语类型，只保留FINTERM",
    )
    embeddingOptions: EmbeddingOptions = Field(
        default_factory=EmbeddingOptions, description="向量数据库配置选项"
    )


# API 端点：术语标准化
@app.post("/api/std", summary="金融术语标准化")
async def standardization(input: TextInput):
    try:
        logger.info(
            f"收到标准化请求: text={input.text[:50]}..., termTypes={input.termTypes}"
        )

        # 验证输入
        if not input.text or len(input.text.strip()) == 0:
            raise HTTPException(status_code=422, detail="输入文本不能为空")

        # 配置术语类型
        term_types = input.termTypes

        try:
            # 使用全局标准化服务实例
            standardized_results = std_service.standardize_terms(input.text, term_types)
        except Exception as e:
            logger.error(f"标准化处理失败: {str(e)}")
            raise HTTPException(status_code=500, detail=f"标准化处理失败: {str(e)}")

        return {
            "message": "金融术语标准化完成",
            "standardized_terms": standardized_results,
        }
    except HTTPException as e:
        # 重新抛出HTTP异常
        raise e
    except Exception as e:
        logger.error(f"标准化请求处理异常: {str(e)}")
        raise HTTPException(status_code=500, detail=f"服务器内部错误: {str(e)}")


if __name__ == "__main__":
    import uvicorn

    uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
